package com.jcroke.DACGraph.utils;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;

import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.traverse.TopologicalOrderIterator;

import com.jcroke.DACGraph.Pnode;

public class GraphVizDotGenerator {

	private String _filename;
	private File _file;
	private DefaultDirectedGraph<Pnode, DefaultEdge> _g;
	ArrayList<String> connections;
	ArrayList<String> inputs;
	ArrayList<String> outputs;
	ArrayList<String> processes;
	ConcurrentHashMap<String, Pnode> _iriToPnode;

	public GraphVizDotGenerator(String filename,
			DefaultDirectedGraph<Pnode, DefaultEdge> g) {
		this._filename = filename;
		this._file = new File(filename);
		this._g = g;
		this.connections = new ArrayList<String>();
		this.inputs = new ArrayList<String>();
		this.outputs = new ArrayList<String>();
		this.processes = new ArrayList<String>();

		if (_file.exists()) {
			_file.delete();
		}
		try {
			_file.createNewFile();
		} catch (IOException e) {
			System.err.println("Could not create file: " + filename + ": "
					+ e.getMessage());
		}
	}

	private void _write(String data) {
		FileWriter writer = null;
		try {
			writer = new FileWriter(_filename, true);
		} catch (IOException e) {
			e.printStackTrace();
		}

		BufferedWriter bufferWritter = new BufferedWriter(writer);
		try {
			bufferWritter.write(data);
		} catch (IOException e) {
			System.err.println("Could not write data to file: "
					+ e.getMessage());
		}
		try {
			bufferWritter.close();
		} catch (IOException e) {
			System.err.println("Could not close FileWriter: " + e.getMessage());
		}
	}

	public void writeHeader() {
		_write("digraph G {\n\n"
				+ "nodesep=.90;\n\n"
				+ "ranksep=\"0.50 equally\";\n\n"
				+ "rankdir=TB;\n\n"
				+ "graph [fontsize=14 labelloc=\"t\" label=\"\" splines=true overlap=false rankdir = \"TB\"];\n\n"
				+ "ratio = auto;\n\n");
	}

	public void writeInputs() {
		StringBuffer sb = new StringBuffer();
		for (String i : inputs) {
			sb.append("\t\t" + i + "\n");
		}

		_write("\tsubgraph cluster_0 {\n" + "\t\tlabel = \"Input fields\";\n"
				+ "\t\tstyle=filled;\n" + "\t\tcolor = \"dodgerblue\";\n"
				+ "\t\tnode [shape=record, color=indianred4, fontsize=8];\n\n"
				+ sb.toString() + "\t}\n");
	}

	public void writeProcesses() {
		StringBuffer sb = new StringBuffer();
		for (String p : processes) {
			sb.append("\t\t" + p + "\n");
		}
		_write("\tsubgraph cluster_1 {\n"
				+ "\t\tlabel = \"Processing Phase\";\n" + "\t\tstyle=filled;\n"
				+ "\t\tcolor = \"gray74\";\n"
				+ "\t\tnode [shape=record, color=forestgreen, fontsize=8];\n\n"
				+ sb.toString() + "\t}\n");
	}

	public void writeOutputs() {
		StringBuffer sb = new StringBuffer();
		for (String o : outputs) {
			sb.append("\t\t" + o + "\n");
		}

		_write("\tsubgraph cluster_2 {\n" + "\t\tlabel = \"Output fields\";\n"
				+ "\t\tstyle=filled;\n" + "\t\tcolor = \"dodgerblue\";\n"
				+ "\t\tnode [shape=record, color=indianred4, fontsize=8];\n\n"
				+ sb.toString() + "\t}\n");
	}

	public void writeTopologicalOrder() {

		TopologicalOrderIterator<Pnode, DefaultEdge> gI = new TopologicalOrderIterator<Pnode, DefaultEdge>(
				_g);

		StringBuffer sb = new StringBuffer("\n\n");
		int i = 0;
		String first = null;
		String second = null;
		Pnode v;

		while (gI.hasNext()) {
			i++;
			v = gI.next();
			if (second == null) {
				first = Pnode.substrIRI(v.getIRI());
				first = first.replace("-", "_");
				sb.append(first);
				if (gI.hasNext()) {
					sb.append(" -> ");
					// we have an edge, increment label
					second = Pnode.substrIRI((gI.next().getIRI()));
					second = second.replace("-", "_");
					sb.append(second);
					sb.append(" [color=\"red\" label = \" " + i
							+ " \" fontcolor = \"red\"]");
				}
			} else {
				first = second;
				sb.append(first);
				sb.append(" -> ");
				second = Pnode.substrIRI(v.getIRI());
				second = second.replace("-", "_");
				sb.append(second);
				sb.append(" [color=\"red\" label = \" " + i
						+ " \" fontcolor = \"red\"]");
			}
			sb.append(";\n");
		}
		_write(sb.toString());
	}

	public void writeConnections() {
		for (String c : connections) {
			_write("\t" + c + "\n");
		}
	}

	public void writeFooter() {
		_write("\n}\n");
	}

	public void createDotFile() {
		TopologicalOrderIterator<Pnode, DefaultEdge> pList = new TopologicalOrderIterator<Pnode, DefaultEdge>(
				_g);
		while (pList.hasNext()) {
			Pnode p = pList.next();
			if (Pnode.substrIRI(p.getIRI()).matches("if-\\d+")) {
				inputs.add(p.toDot(connections));
			} else if (Pnode.substrIRI(p.getIRI()).matches("of-\\d+")) {
				outputs.add(p.toDot(connections));
			} else {
				processes.add(p.toDot(connections));
			}

		}

		writeHeader();
		writeOutputs();
		writeInputs();
		writeProcesses();
		writeConnections();
		//writeTopologicalOrder();
		writeFooter();
	}

	public void setGraph(DefaultDirectedGraph<Pnode, DefaultEdge> g) {
		this._g = g;
	}
}
